using NBehave.Spec.MbUnit;
using Pentago.Core;
using Context = MbUnit.Framework.TestFixtureAttribute;
using Specification = MbUnit.Framework.TestAttribute;
using MultiScenarioSpecification = MbUnit.Framework.RowTestAttribute;
using Scenario = MbUnit.Framework.RowAttribute;

namespace Pentago.Specifications
{
    [Context]
    public class GameBlockSpecifications : SpecBase
    {
        [Specification]
        public void Should_store_identifier()
        {
            var gameBlock = new GameBlock(1);
            gameBlock.Identifier.ShouldEqual(1);
        }

        [Specification]
        public void Should_set_whole_block_to_empty_upon_creation()
        {
            var gameBlock = new GameBlock(1);
            for (var location = 1; location <= 9; location++)
                gameBlock.IsOccupiedBy(location, Marble.Empty).ShouldBeTrue();
        }

        [MultiScenarioSpecification]
        [Scenario(0)]
        [Scenario(10)]
        public void Should_not_allow_access_outside_the_block(int location)
        {
            var gameBlock = new GameBlock(1);
            (typeof (InvalidPositionException)).ShouldBeThrownBy(() => gameBlock.Place(location, Marble.Black));
        }

        [Specification]
        public void Should_store_marble_location_when_placed()
        {
            var gameBlock = new GameBlock(1);

            gameBlock.Place(3, Marble.Black);
            gameBlock.IsOccupiedBy(3, Marble.Black).ShouldBeTrue();
        }

        [Specification]
        public void Should_move_marble_positions_one_notch_clockwise()
        {
            // clockwise
            // B W _        B _ B
            // _ _ W   =>   W _ W
            // B W _        _ W _

            var gameBlock = new GameBlockSetup().AddWhiteMarblesToLocations(2, 6, 8).AddBlackMarblesToLocations(1, 7).Create();

            gameBlock.Twist(Direction.Clockwise);

            new GameBlockSetup().AddWhiteMarblesToLocations(4, 6, 8).AddBlackMarblesToLocations(1, 3)
                 .ShouldContainTheSameMarblesAs(gameBlock);
        }

        [Specification]
        public void Should_move_marble_positions_one_notch_counterclockwise()
        {
            // counter-clockwise
            // B W _        _ W _
            // _ _ W   =>   W _ W
            // B W _        B _ B

            var gameBlock = new GameBlockSetup().AddWhiteMarblesToLocations(2, 6, 8).AddBlackMarblesToLocations(1, 7).Create();

            gameBlock.Twist(Direction.CounterClockwise);

            new GameBlockSetup().AddWhiteMarblesToLocations(2, 4, 6).AddBlackMarblesToLocations(7, 9)
                .ShouldContainTheSameMarblesAs(gameBlock);
        }

        [Specification]
        public void Should_barf_when_spot_already_taken()
        {
            var gameBlock = new GameBlock(1);
            gameBlock.Place(1, Marble.Black);

            (typeof(PositionOccupiedException)).ShouldBeThrownBy(() => gameBlock.Place(1, Marble.White));
        }
    }
}